package org.chen.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.chen.model.CommentBatch;
import org.chen.model.CommentTask;
import org.chen.enu.BatchStatus;
import org.chen.enu.TaskStatus;
import org.chen.mapper.CommentBatchMapper;
import org.chen.mapper.CommentTaskMapper;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@RequiredArgsConstructor
public class BatchStatsManager {
    private static final String BATCH_SUCCESS_COUNTER = "counter:batch:success:";
    private static final String BATCH_FAILURE_COUNTER = "counter:batch:failure:";
    private static final String COUNTER_KEY_PREFIX = "counter:batch:";
    private static final int COUNTER_EXPIRE_DAYS = 7;  // 计数器7天后过期

    private final StringRedisTemplate redisTemplate;

    private final CommentTaskMapper taskMapper;

    private final CommentBatchMapper batchMapper;

    @Autowired
    private RedissonClient redissonClient;

    private static final String BATCH_LOCK_PREFIX = "lock:batch:";

    /**
     * 增加成功或失败计数
     */
    public void incrementCounter(String batchNo, boolean success) {
        try {
            String key = success ? BATCH_SUCCESS_COUNTER + batchNo : BATCH_FAILURE_COUNTER + batchNo;
            redisTemplate.opsForValue().increment(key);
            redisTemplate.expire(key, COUNTER_EXPIRE_DAYS, TimeUnit.DAYS);
        } catch (Exception e) {
            log.error("增加计数失败: batchNo={}, success={}", batchNo, success, e);
        }
    }

    /**
     * 更新批次统计信息
     */
    public void updateBatchStats(String batchNo, boolean success) {
        try {
            // 获取Redis计数器的值
            String successKey = BATCH_SUCCESS_COUNTER + batchNo;
            String failureKey = BATCH_FAILURE_COUNTER + batchNo;
            
            Long redisSuccessCount = getCounterValue(successKey);
            Long redisFailureCount = getCounterValue(failureKey);

            // 从数据库获取实际计数
            long dbSuccessCount = taskMapper.selectCount(
                    new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .eq("status", TaskStatus.SUCCESS.name())
            );

            long dbFailureCount = taskMapper.selectCount(
                    new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .eq("status", TaskStatus.FAILED.name())
            );

            // 使用最大值确保不丢失计数
            long finalSuccessCount = Math.max(
                redisSuccessCount != null ? redisSuccessCount : 0,
                dbSuccessCount
            );

            long finalFailureCount = Math.max(
                redisFailureCount != null ? redisFailureCount : 0,
                dbFailureCount
            );

            updateBatch(batchNo, finalSuccessCount, finalFailureCount, success);

            if (success) {
                // 更新Redis计数器确保一致性
                redisTemplate.opsForValue().set(successKey, String.valueOf(finalSuccessCount));
                redisTemplate.opsForValue().set(failureKey, String.valueOf(finalFailureCount));
                redisTemplate.expire(successKey, COUNTER_EXPIRE_DAYS, TimeUnit.DAYS);
                redisTemplate.expire(failureKey, COUNTER_EXPIRE_DAYS, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            log.error("更新批次统计信息失败: {}", batchNo, e);
        }
    }

    private Long getCounterValue(String key) {
        try {
            String value = redisTemplate.opsForValue().get(key);
            return value != null ? Long.parseLong(value) : null;
        } catch (Exception e) {
            log.error("获取计数器值失败: {}", key, e);
            return null;
        }
    }

    private void updateBatch(String batchNo, long successCount, long failureCount, boolean success) {
        CommentBatch batch = batchMapper.selectByBatchNo(batchNo);
        if (batch != null) {
            batch.setSuccessCount((int) successCount);
            batch.setFailureCount((int) failureCount);

            // 检查待处理任务
            long pendingCount = taskMapper.selectCount(
                    new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .in("status", TaskStatus.PENDING.name(), TaskStatus.PROCESSING.name())
            );

            // 如果没有待处理任务，更新最终状态
            if (pendingCount == 0) {
                if (success) {
                    batch.setStatus(determineBatchStatus(batch));
                }
            }

            batch.setUpdateTime(LocalDateTime.now());
            batchMapper.updateBatch(batch);
        }
    }

    /**
     * 确定批次最终状态
     */
    private String determineBatchStatus(CommentBatch batch) {
        if (batch.getFailureCount() == 0 &&
                Objects.equals(batch.getSuccessCount(), batch.getTotalCount())) {
            return BatchStatus.COMPLETED.name();
        } else if (batch.getSuccessCount() > 0) {
            return BatchStatus.PARTIALLY_COMPLETED.name();
        } else {
            return BatchStatus.FAILED.name();
        }
    }

    /**
     * 批量删除多个批次的计数器
     * @param batchNos 批次号列表
     */
    public void deleteCountersForBatch(List<String> batchNos) {
        if (CollectionUtils.isEmpty(batchNos)) {
            return;
        }

        try {
            Set<String> keys = new HashSet<>();
            for (String batchNo : batchNos) {
                keys.add(BATCH_SUCCESS_COUNTER + batchNo);
                keys.add(BATCH_FAILURE_COUNTER + batchNo);
            }
            redisTemplate.delete(keys);
            log.info("Deleted counters for batches: {}", keys);
        } catch (Exception e) {
            log.error("Failed to delete counters for batches: {}", batchNos, e);
        }
    }

    /**
     * 删除单个批次的计数器（保留原方法兼容现有代码）
     */
    public void deleteCountersForBatch(String batchNo) {
        if (StringUtils.isEmpty(batchNo)) {
            return;
        }
        deleteCountersForBatch(Collections.singletonList(batchNo));
    }

    /**
     * 更新批次状态
     */
    public void updateBatchStatus(String batchNo, BatchStatus status) {
        batchMapper.updateStatus(batchNo, status.name(), LocalDateTime.now());
    }

    /**
     * 更新批次进度
     */
    public void updateBatchProgress(String batchNo) {
        RLock lock = redissonClient.getLock(BATCH_LOCK_PREFIX + batchNo);
        try {
            if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                log.warn("获取批次锁失败: {}", batchNo);
                return;
            }

            try {
                updateBatchStats(batchNo, true);
            } finally {
                lock.unlock();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("等待批次锁时被中断", e);
        }
    }

    /**
     * 同步批次状态
     * 用于系统启动时或手动触发时同步状态
     */
    public void syncBatchStatus(String batchNo) {
        RLock lock = redissonClient.getLock(BATCH_LOCK_PREFIX + batchNo);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                try {
                    updateBatchStats(batchNo, false);
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("同步批次状态时被中断: {}", batchNo, e);
        }
    }

    /**
     * 最终确认批次状态
     */
    public void finalizeBatchStatus(String batchNo) {
        try {
            // 再次检查是否还有未完成的任务
            long pendingCount = taskMapper.selectCount(
                    new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .eq("status", TaskStatus.PENDING.name())
            );

            CommentBatch batch = batchMapper.selectByBatchNo(batchNo);
            if (batch != null) {
                BatchStatus finalStatus;
                if (pendingCount > 0) {
                    finalStatus = BatchStatus.PARTIALLY_COMPLETED;
                    log.warn("批次{}还有{}个任务未完成", batchNo, pendingCount);
                } else if (batch.getSuccessCount() + batch.getFailureCount() == batch.getTotalCount()) {
                    finalStatus = BatchStatus.COMPLETED;
                    log.info("批次{}全部完成", batchNo);
                } else {
                    log.warn("批次{}统计数不匹配: 总数:{}, 成功:{}, 失败:{},即将修正统计",
                            batchNo, batch.getTotalCount(),
                            batch.getSuccessCount(), batch.getFailureCount());

                    Long successCount = taskMapper.selectCount(new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .eq("status", "SUCCESS"));

                    Long failedCount = taskMapper.selectCount(new QueryWrapper<CommentTask>()
                            .eq("batch_no", batchNo)
                            .eq("status", "FAILED"));

                    log.warn("批次{}修正后的统计: 总数:{}, 成功:{}, 失败:{}",
                            batchNo, batch.getTotalCount(),
                            successCount, failedCount);

                    finalStatus = BatchStatus.COMPLETED;

                    batch.setSuccessCount(Math.toIntExact(successCount));
                    batch.setFailureCount(Math.toIntExact(failedCount));

                    batchMapper.updateById(batch);

                    deleteCountersForBatch(batchNo);
                }
                updateBatchStatus(batchNo, finalStatus);
            }
        } catch (Exception e) {
            log.error("更新批次最终状态失败: {}", e.getMessage());
        }
    }
}